package com.gullmall.search.service.impl;

import com.gullmall.search.config.ElasticsearchConfig;
import com.gullmall.search.constant.EsConstant;
import com.gullmall.search.entity.vo.SearchParams;
import com.gullmall.search.entity.vo.SearchResult;
import com.gullmall.search.service.MallSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class MallSearchServiceImpl implements MallSearchService {


    @Resource(name = "elasticsearchClient")
    private RestHighLevelClient restHighLevelClient;

    /**
     * @param searchParams 查询参数
     * @return
     */
    @Override
    public SearchResult search(SearchParams searchParams) {
        SearchRequest searchRequest = buildSearchRequest(searchParams);
        SearchResult searchResult = null;
        try {

            //发送请求
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticsearchConfig.COMMON_OPTIONS);
            searchResult = buildSearchResult(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return searchResult;
    }

    /**
     * 构建搜索请求
     * 模糊匹配,过滤(按照属性,分类,品牌,价格区间,库存),排序,分页,高亮,聚合分析
     */
    private SearchRequest buildSearchRequest(SearchParams searchParams) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //must模糊匹配 和 高亮
        if (!StringUtils.isEmpty(searchParams.getKeyword())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle", searchParams.getKeyword()));
            searchSourceBuilder.highlighter(new HighlightBuilder().field("skuTitle")
                    .preTags("<b style='color:red;'>").postTags("</b>"));
        }
        //filter过滤 按照分类
        if (searchParams.getCatalogId() != null) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId", searchParams.getCatalogId()));
        }
        //filter过滤 按照多个品牌id
        if (searchParams.getBrandId() != null && searchParams.getBrandId().size() > 0) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("brandId", searchParams.getBrandId()));
        }
        //按照 库存 过滤,如果是1则只查有库存的,否则全查
        if (searchParams.getHasStock() != null && searchParams.getHasStock() == 1) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("hasStock", true));
        }
        //按照 价格区间 字符串格式: skuPrice=1_500(1到500) skuPrice=_500(500以内) skuPrice=500_(500以上)
        if (!StringUtils.isEmpty(searchParams.getSkuPrice())) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");
            String skuPrice = searchParams.getSkuPrice();
            List<String> split = Arrays.asList(skuPrice.split("[_]")).stream().filter(s1 -> !StringUtils.isEmpty(s1.trim())).collect(Collectors.toList());
            //区间 1_500模式
            if (Pattern.compile("^\\d+[_]{1}\\d+$").matcher(searchParams.getSkuPrice()).find()) {
                rangeQuery.gte(split.get(0)).lte(split.get(1));
            } else if (Pattern.compile("^[_]{1}\\d+$").matcher(searchParams.getSkuPrice()).find()) {
                //小于模式 _500(500以内)
                rangeQuery.lte(split.get(0));
            } else if (Pattern.compile("^\\d+[_]{1}$").matcher(searchParams.getSkuPrice()).find()) {
                //小于模式 500_(500以上)
                rangeQuery.gte(split.get(0));
            }
            boolQueryBuilder.filter(rangeQuery);
        }

        //按照属性 过滤
        if (searchParams.getAttrs() != null && searchParams.getAttrs().size() > 0) {
            for (String attrStr : searchParams.getAttrs()) {
                BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery();
                String[] split = attrStr.split("_");
                String attrId = split[0];
                String[] attrValues = split[1].split(":");//可能有多个属性值,通过冒号分隔
                nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId", attrId));
                nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrValue", attrValues));
                NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None);
                boolQueryBuilder.filter(nestedQueryBuilder);
            }
        }
        //封装查询语句
        searchSourceBuilder.query(boolQueryBuilder);

        //排序
        if (StringUtils.isNotEmpty(searchParams.getSort())) {
            String str = searchParams.getSort();
            List<String> split = Arrays.asList(str.split("_"));
            searchSourceBuilder.sort(split.get(0), SortOrder.fromString(split.get(1)));
        }
        Integer pageNum = searchParams.getPageNum();
        if (pageNum == null || pageNum < 1) {
            pageNum = 1;
        }
        //分页 每页60条
        searchSourceBuilder.from((pageNum - 1) * 60);
        searchSourceBuilder.size(60);

        //聚合


        System.out.println("构建的DSL语句" + searchSourceBuilder.toString());

        SearchRequest searchRequest = new SearchRequest(new String[]{EsConstant.ProductIndex.INDEX_PRODUCT.getValue()}, searchSourceBuilder);
        return searchRequest;
    }

    //构建结果
    private SearchResult buildSearchResult(SearchResponse response) {
        return null;
    }


}
